package ru.geyes.screw.collections;

import ru.geyes.screw.closures.Function1B;
import ru.geyes.screw.closures.Function1;
import ru.geyes.screw.closures.Function1V;
import ru.geyes.screw.tuples.Tuple2;

import java.util.ArrayList;
import java.util.List;
import java.util.Collection;

/**
 * @author alex
 *         date 17.05.2008
 *         time 21:33:43
 */
public class ArrayListX<T> extends ArrayList<T> implements ListX<T> {
    public ArrayListX(int initialCapacity) {
        super(initialCapacity);
    }

    public ArrayListX() {
        super();
    }

    public ArrayListX(Collection<? extends T> c) {
        super(c);
    }

    public List<T> getList() {
        return new ArrayList<T>(this);
    }

    public Option<T> getFirst() {
        if (this.size() > 0)
            return Option.some(this.get(0));
        else
            return Option.none();
    }

    public Option<T> getLast() {
        if (this.size() > 0)
            return Option.some(this.get(this.size() - 1));
        else
            return Option.none();
    }

    public ListX<T> filter(Function1B filterF) {
        ListX<T> list = new ArrayListX<T>();
        for (T o : this)
            if (filterF.apply(o)) list.add(o);
        return list;
    }

    public <F> ListX<F> map(Function1<F, T> mapperF) {
        ListX<F> list =  new ArrayListX<F>();
        for (T t : this) 
            list.add(mapperF.apply(t));
        return list;
    }

    public <F> MapX<F, T> map2Map(final Function1<Tuple2<F, T>, T> mapperF) {
        final MapX<F, T> map = new HashMapX<F,T>();
        this.map(new Function1<Tuple2<F, T>, T>() {
            public Tuple2<F, T> apply(T param) {
                return mapperF.apply(param);
            }
        }).foreach(new Function1V<Tuple2<F, T>>() {
            public void apply(Tuple2<F, T> p) {
                map.put(p._0(), p._1());
            }
        });
        return map;
    }

    public void foreach(Function1V<T> f) {
        for (T t : this) {
            f.apply(t);
        }
    }

    public ListX<T> cloneList() {
        return new ArrayListX<T>(this);
    }

    public ListX<T> append(T o) {
        this.add(o);
        return this;
    }

    public ListX<T> insert(T o, int pos) {
        this.add(pos, o);
        return this;
    }

    public ListX<T> push(T o) {
        this.add(0, o);
        return this;
    }

    public ListX<T> appendUnmod(T o) {
        ListX<T> list = new ArrayListX<T>(this);
        list.append(o);
        return list;
    }

    public ListX<T> insertUnmod(T o, int pos) {
        ListX<T> list = new ArrayListX<T>(this);
        list.insert(o, pos);
        return list;
    }

    public ListX<T> pushUnmod(T o) {
        ListX<T> list = new ArrayListX<T>(this);
        list.push(o);
        return list;
    }

    public ListX<T> clone() {
        return new ArrayListX<T>(this);
    }
}
